#include <cstdint>
#include <endian.h> // for endianness conversion
#include <cstring>

/**
 * 网络包解码类 - 大端字节序
 * 支持的类型包括：uint8_t, uint16_t, uint32_t, uint64_t, unsigned char *
 * 
 * 内部基于 unsigned char数组实现
 * 支持 read_u8, read_u16, read_u32, read_u64, read_buffer 等方法
 * 支持 readable_bytes() 方法获取可读数据长度
 * 支持 reset() 方法重置解码状态
 */


class decodebuffer2 {
public:
    explicit decodebuffer2(const unsigned char * data, size_t len)
        : buffer_(data), buffer_size_(len), read_index_(0) {}

    size_t readable_bytes() const { return buffer_size_ - read_index_; }
    void reset() { read_index_ = 0; }

public:
    // 特化后的函数，方便调用
    bool read_u8(uint8_t &x) { return read_uint(x); }
    bool read_u16(uint16_t &x) { return read_uint(x); }
    bool read_u32(uint32_t &x) { return read_uint(x); }
    bool read_u64(uint64_t &x) { return read_uint(x); }

    bool read_buffer(unsigned char * data, size_t len) {
        if (readable_bytes() >= len) {
            memcpy(data, peek(), len);
            retrieve(len);
            return true;
        }
        return false;
    }

private:
    // 模板函数，用于从缓冲区读取不同类型的无符号整数
    template <typename T>
    bool read_uint(T &x) {
        if (readable_bytes() >= sizeof(T)) {
            if constexpr (sizeof(T) == 1) {
                // 单字节数据无需字节序转换
                x = *peek();
            } else {
                memcpy(&x, peek(), sizeof(T));
                // 根据类型进行字节序转换
                if constexpr (sizeof(T) == 2) {
                    x = be16toh(x);
                } else if constexpr (sizeof(T) == 4) {
                    x = be32toh(x);
                } else if constexpr (sizeof(T) == 8) {
                    x = be64toh(x);
                }
            }
            retrieve(sizeof(T));
            return true;
        }
        return false;
    }

    // 读索引移动
    void retrieve(size_t len) { read_index_ += len; }

    // 当前可读数据的起始地址
    const unsigned char* peek() const { return buffer_ + read_index_; }

private:
    const unsigned char *buffer_;
    size_t buffer_size_;
    size_t read_index_ = 0;
};

